#include "stdafx.h"
#include "TrajectoryBuilder.h"

#include "OrbitElemTransform.h"
#include "RadaParam.h"
#include "EphemParam.h"
#include "SimpleFile.h"
#include "EphemWrapper.h"
#include "StartCalcParamDlg.h"
#include "GridParam.h"
#include "Drawer.h"

CTrajectoryBuilder::CTrajectoryBuilder(OnErrorNotifyInterface *pNotyInterface)
: m_pNotyInterface(pNotyInterface)
{
	m_bodyRefPos.GM = 0.0;
	{
		int wasRead = 0;
		CSimpleFile InFile(_T("param.start.txt"), _T("r"));
		wasRead += _ftscanf(InFile, _T("%le"), &m_dStartTime);
		for(int i = 0; i< sizeof(m_bodyRefPos.x)/sizeof(m_bodyRefPos.x[0]); i++)
			wasRead += _ftscanf(InFile, _T("%le"), m_bodyRefPos.x + i);

		for(int i = 0; i< sizeof(m_bodyRefPos.v)/sizeof(m_bodyRefPos.v[0]); i++)
			wasRead += _ftscanf(InFile, _T("%le"), m_bodyRefPos.v + i);
		wasRead += _ftscanf(InFile, _T("%le"), &m_dEndTime);
		if(wasRead != 8)
			throw CCustomException(_T("error reading input param %d read must be 8"), wasRead);
	}
	m_dRefRangeKm = 10.0; 
}

CTrajectoryBuilder::~CTrajectoryBuilder(void)
{
	if(m_pCalcThreadHolder.get())
		m_pCalcThreadHolder->Close();
}

bool CTrajectoryBuilder::Calc(IApproachHolder *pAppHolderInterface, NewCalcParam *pCalcParam )
{
	if(IsWork())
		return false;

	COrbitElemTransform::Elements elem;
	COrbitElemTransform::CoordToElem( 0.0, m_bodyRefPos.x, m_bodyRefPos.v, elem, COrbitElemTransform::dEclEcvAngle);
	double A = COrbitElemTransform::DMOTA(elem.DMOT, 0.0);

	int nOrbitCount = 1;
 	double dShift = CEphemWrapper::KMtoAU( 0.0 );
	double dLoBound = -CEphemWrapper::KMtoAU(m_dRefRangeKm);
	double dHiBound =  CEphemWrapper::KMtoAU(m_dRefRangeKm);
	
	if(pCalcParam)
	{
		double dCenter = (pCalcParam->dFrom + pCalcParam->dTo) / 2.0;
		dShift = dCenter - A;
		dLoBound = pCalcParam->dFrom - dCenter;
		dHiBound = pCalcParam->dTo - dCenter;
	}
	
	{
		CStartCalcParamDlg dlg;
		dlg.m_dFromRange = dLoBound;
		dlg.m_dShift = dShift;
		dlg.m_dToRange = dHiBound;
		dlg.m_dFromDefTime = m_dStartTime;
		dlg.m_dToDefTime = m_dEndTime;
		dlg.m_bUseSelectTime = FALSE;
		if(pCalcParam)
		{
			dlg.m_dFromDefTime = pCalcParam->dEnd;
			dlg.m_dToDefTime = pCalcParam->dEnd;
		}
		if(dlg.DoModal() != IDOK)
			return false;

		dLoBound = dlg.m_dFromRange;
		dShift = dlg.m_dShift;
		dHiBound = dlg.m_dToRange;
		nOrbitCount = dlg.m_nCount;
	}

	double step = 0.0;
	if(nOrbitCount > 1)
		step = (dHiBound - dLoBound) / (nOrbitCount - 1);

	double param = A + dShift + dLoBound;
	ListTrajParamPtr listTrajParamPtr;
	for( int i = 0; i < nOrbitCount; ++i, param+=step )
	{
		elem.DMOT = COrbitElemTransform::ADMOT(param, 0.0);

		TrajParam::Ptr pTrajParam(new TrajParam);

		pTrajParam->dStart = m_dStartTime;
		pTrajParam->dEnd = m_dEndTime;
		pTrajParam->dParamVal = param;
		pTrajParam->elem = elem;
		pTrajParam->pApproachHolder = pAppHolderInterface;

		listTrajParamPtr.push_back(pTrajParam);
	}

	m_pCalcThreadHolder = CCalcThreadHolderAP(new CCalcThreadHolder(listTrajParamPtr, m_pNotyInterface));
	return true;
}

bool CTrajectoryBuilder::IsWork() const
{
	return !(m_pCalcThreadHolder.get() == NULL || m_pCalcThreadHolder->IsThreadDone());
}

bool CTrajectoryBuilder::GetTimeRange(double &dStart, double &dTo)
{
	dStart = m_dStartTime;
	dTo = m_dEndTime;
	return true;
}

bool CTrajectoryBuilder::GetRefRange(CGridParam * param)
{
	if(param == NULL)
		return false;

	COrbitElemTransform::Elements elem;
	COrbitElemTransform::CoordToElem( 0.0, m_bodyRefPos.x, m_bodyRefPos.v, elem, COrbitElemTransform::dEclEcvAngle);
	double A = COrbitElemTransform::DMOTA(elem.DMOT, 0.0);
	double F = A - CEphemWrapper::KMtoAU(m_dRefRangeKm);
	double T = A + CEphemWrapper::KMtoAU(m_dRefRangeKm);

	*param = CGridParam(m_dStartTime, m_dEndTime, F, T, A);
	return true;
}